﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace VTQuery.Net.Print
{
    /// <summary>
    /// 用于打印不规则的表格，目前只支持单表格
    /// </summary>
    public class TablePrintDocument : PrintDocument
    {
        public TablePrintDocument()
        {
            this.PrintPage += new PrintPageEventHandler(TablePrint_PrintPage);
        }

        public void Preview()
        {
            PrintPreviewDialog previewDialog = new PrintPreviewDialog();
            previewDialog.Document = this;
            previewDialog.FindForm().WindowState = FormWindowState.Maximized;
            previewDialog.FindForm().Text = title;
            previewDialog.PrintPreviewControl.Zoom = 1;
            previewDialog.ShowDialog();
        }

        Font titleFont = new Font("宋体", 18, FontStyle.Regular);
        Font subTitleFont = new Font("宋体", 12, FontStyle.Regular);
        Font cellFont = new Font("宋体", 12, FontStyle.Regular);
        Brush textBrush = Brushes.Black;
        IList<TablePrintCell> cells;
        string title;
        string subTitle;
        float titleMarginLeft = 300;
        float subTitleMarginLeft = 450;
        int tableMarginUnderTitle = 20;
        int[] columnWidth;
        //int[] rowHeight;
        int beginX = 30;
        int beginY = 30;
        Pen borderPen;
        int defaultCellHeight = 50;
        int pageIndex = 1;


        public string Title
        {
            set { title = value; }
        }
        public string SubTitle
        {
            set { subTitle = value; }
        }
        /// <summary>
        /// 标题字体
        /// </summary>
        public Font TitleFont
        {
            get { return titleFont; }
            set { titleFont = value; }
        }
        /// <summary>
        /// 副标字体
        /// </summary>
        public Font SubTitleFont
        {
            get { return subTitleFont; }
            set { subTitleFont = value; }
        }
        public float TitleMarginLeft
        {
            get { return titleMarginLeft; }
            set { titleMarginLeft = value; }
        }
        public float SubTitleMarginLeft
        {
            get { return subTitleMarginLeft; }
            set { subTitleMarginLeft = value; }
        }
        public int TableMarginUnderTitle
        {
            get { return tableMarginUnderTitle; }
            set { tableMarginUnderTitle = value; }
        }

        /// <summary>
        /// 字体
        /// </summary>
        public Font CellFont
        {
            get { return cellFont; }
            set { cellFont = value; }
        }
        /// <summary>
        /// 文本笔刷
        /// </summary>
        public Brush TextBrush
        {
            get { return textBrush; }
            set { textBrush = value; }
        }
        public IList<TablePrintCell> Cells
        {
            set { cells = value; }
        }
        public int[] ColumnWidth
        {
            set { columnWidth = value; }
            get { return columnWidth; }
        }
        //public int[] RowHeight
        //{
        //    set { rowHeight = value; }
        //}
        public int BeginX
        {
            get { return beginX; }
            set { beginX = value; }
        }

        public int BeginY
        {
            get { return beginY; }
            set { beginY = value; }
        }
        public Pen BorderPen
        {
            get { return borderPen; }
            set { borderPen = value; }
        }


        int rowIndex, columnIndex;
        int x, y;
        void TablePrint_PrintPage(object sender, PrintPageEventArgs e)
        {
            if (columnWidth == null)
                throw new ArgumentNullException("columnWidth");
            if (cells == null || cells.Count == 0)
                throw new ArgumentNullException("cells is null or empty");
            x = beginX;
            y = beginY;
            if (!string.IsNullOrEmpty(title))
            {
                e.Graphics.DrawString(title, titleFont, textBrush, x + titleMarginLeft, y);
                y += titleFont.Height + 10;
            }
            if (!string.IsNullOrEmpty(subTitle))
            {
                e.Graphics.DrawString(subTitle, subTitleFont, textBrush, x + subTitleMarginLeft, y);
                y += subTitleFont.Height;
            }
            y += tableMarginUnderTitle;
            rowIndex = columnIndex = 0;
            foreach (TablePrintCell cell in cells)
            {
                DrawCell(cell, e);
            }

        }

        void DrawCell(TablePrintCell cell, PrintPageEventArgs e)
        {
            int cellWidth = 0;
            int cellHeight = 0;
            for (int i = cell.BeginColumn; i <= cell.EndColumn; i++)
            {
                cellWidth += columnWidth[i];
            }
            for (int i = cell.BeginRow; i <= cell.EndRow; i++)
            {
                cellHeight += cell.Height <= 0 ? defaultCellHeight : cell.Height;
            }
            if (borderPen != null)
            {


                if (columnIndex == 0)//draw left
                {
                    e.Graphics.DrawLine(borderPen, x, y, x, y + cellHeight);
                }
                if (rowIndex == 0)//draw top
                {
                    e.Graphics.DrawLine(borderPen, x, y, x + cellWidth, y);
                }
                //draw right
                e.Graphics.DrawLine(borderPen, x + cellWidth, y, x + cellWidth, y + cellHeight);
                //draw bottom
                e.Graphics.DrawLine(borderPen, x, y + cellHeight, x + cellWidth, y + cellHeight);
            }
            //draw text
            if (!string.IsNullOrEmpty(cell.Text) && pageIndex == 1)
            {
                //StringFormat sf = new StringFormat(0);
                //sf.Alignment = StringAlignment.Near;
                //sf.FormatFlags = StringFormatFlags.LineLimit;
                e.Graphics.DrawString(cell.Text, cellFont, textBrush, Convert.ToSingle(x + cell.PaddingLeft),
                                      Convert.ToSingle(y + cell.PaddingTop));
            }
            columnIndex = cell.EndColumn;
            if (columnIndex == columnWidth.Length - 1)
            {
                rowIndex = cell.EndRow;
                columnIndex = 0;
                x = beginX;
                y += cellHeight;
            }
            else
                x += cellWidth;
            if ((float)y >= base.DefaultPageSettings.PrintableArea.Height)
            {
                e.HasMorePages = true;
                pageIndex++;
            }
        }
    }

    public class TablePrintCell
    {
        public TablePrintCell() { }
        public TablePrintCell(int beginColumn, int endColumn, int beginRow, int endRow, string text)
        {
            this.beginColumn = beginColumn;
            this.endColumn = endColumn;
            this.beginRow = beginRow;
            this.endRow = endRow;
            this.text = text;
        }
        public TablePrintCell(int beginColumn, int endColumn, int beginRow, int endRow, string text, int height)
            : this(beginColumn, endColumn, beginRow, endRow, text)
        {
            this.height = height;
            this.paddingTop = (height - textFont.Height) / 2;
        }
        public TablePrintCell(int beginColumn, int endColumn, int beginRow, int endRow, string text, int height, int paddingLeft, int paddingTop)
            : this(beginColumn, endColumn, beginRow, endRow, text, height)
        {
            this.paddingLeft = paddingLeft;
            this.paddingTop = paddingTop;
        }

        public TablePrintCell(int column, int row, string text)
            : this(column, column, row, row, text)
        {
        }

        public static void AppendOneRowCellByCell(IList<TablePrintCell> cells, int rowIndex, params string[] cellText)
        {
            string[] cellTexts = new string[cellText.Length];
            for (int i = 0; i < cellTexts.Length; i++)
                cellTexts[i] = cellText[i];
            AppendOneRowCellByCell(cells, rowIndex, 0, cellTexts, null);
        }
        public static void AppendOneRowCellByCell(IList<TablePrintCell> cells, int rowIndex, int cellHeight, string[] cellTexts, int[] cellWidths)
        {
            if (rowIndex < 0)
                throw new Exception("rowIndex must greater than 0");
            int baseIndex = cells.Count;
            int maxCellHeight = 0;
            int maxCellPaddingTop = 0;
            for (int i = 0; i < cellTexts.Length; i++)
            {
                TablePrintCell cell = new TablePrintCell(i, i, rowIndex, rowIndex, cellTexts[i]);
                //wrap临时解决方案
                string cellText = cell.Text;
                int textRows = 1;
                if (Regex.IsMatch(cellText, "[\u4e00-\uf900]") && cellWidths != null)
                {
                    int textLength = cellText.Length;
                    int rowMaxCharacters = Convert.ToInt32(Math.Ceiling(cellWidths[i] / (cell.Font.Size + cell.Font.Size / 2)));
                    textRows = textLength % rowMaxCharacters == 0
                                ? textLength / rowMaxCharacters
                                : textLength / rowMaxCharacters + 1;
                    if (textRows == 0) textRows = 1;
                    for (int j = 1; j < textRows; j++)
                    {
                        int index = rowMaxCharacters * j + j - 1;
                        if (index < textLength)
                            cellText = cellText.Insert(index, "\n");
                    }
                }
                cell.Text = cellText;
                if (cellHeight > 0)
                {
                    int currentHeight = cellHeight * textRows;
                    if (maxCellHeight < currentHeight)
                    {
                        maxCellHeight = currentHeight;
                        maxCellPaddingTop = (currentHeight - cell.Font.Height * textRows) / 2;
                    }
                }
                cells.Add(cell);
            }
            if (cellHeight > 0)
            {
                for (int i = baseIndex; i < cells.Count; i++)
                {
                    cells[i].Height = maxCellHeight;
                    cells[i].PaddingTop = maxCellPaddingTop;
                }
            }
        }

        Font textFont = new Font("宋体", 12, FontStyle.Regular);
        Brush textBrush;
        int beginColumn;
        int endColumn;
        int beginRow;
        int endRow;
        string text;
        int paddingLeft = 4;
        int paddingTop = 4;
        int height = 30;


        /// <summary>
        /// 字体
        /// </summary>
        public Font Font
        {
            get { return textFont; }
            set { textFont = value; }
        }
        /// <summary>
        /// 笔刷
        /// </summary>
        public Brush TextBrush
        {
            get { return textBrush; }
            set { textBrush = value; }
        }
        public int BeginColumn
        {
            get { return beginColumn; }
            set { beginColumn = value; }
        }

        public int EndColumn
        {
            get { return endColumn; }
            set { endColumn = value; }
        }

        public int BeginRow
        {
            get { return beginRow; }
            set { beginRow = value; }
        }

        public int EndRow
        {
            get { return endRow; }
            set { endRow = value; }
        }

        public string Text
        {
            get { return text; }
            set { text = value; }
        }

        public int PaddingLeft
        {
            get { return paddingLeft; }
            set { paddingLeft = value; }
        }

        public int PaddingTop
        {
            get { return paddingTop; }
            set { paddingTop = value; }
        }
        public int Height
        {
            get { return height; }
            set
            {
                height = value;
                if (textFont != null)
                    paddingTop = (height - textFont.Height) / 2;
            }
        }
    }
}